use clap::Parser;
use procfs::process::Process;
use std::string::String;
use std::sync::Mutex;

use actix_web::{middleware, web, App, HttpServer};
use prometheus_client::metrics::family::Family;
use prometheus_client::registry::Registry;

mod selfstat;
pub use crate::selfstat::*;

mod process;
pub use crate::process::*;

/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    /// Name of Ports
    #[arg(short, long, default_value_t = 8080)]
    ports: u16,

    /// addr , ipv4
    #[arg(short, long, default_value = "127.0.0.1")]
    addr: String,

    /// logger level
    #[arg(short, long, default_value = "debug")]
    level: String,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let args = Args::parse();

    env_logger::init_from_env(env_logger::Env::new().default_filter_or(args.level));

    log::info!(
        "starting HTTP server at http://{}:{}",
        args.addr,
        args.ports
    );

    let me = Process::myself().unwrap();
    let me_stat = me.stat().unwrap();
    println!("PID: {}", me.pid);

    let page_size = procfs::page_size() as u64;
    println!("Memory page size: {}", page_size);

    println!("== Data from /proc/self/stat:");
    println!("Total virtual memory used: {} bytes", me_stat.vsize);
    println!(
        "Total resident set: {} pages ({} bytes)",
        me_stat.rss,
        me_stat.rss as u64 * page_size
    );
    //
    let metrics = web::Data::new(OwnMetrics {
        requests: Family::default(),
        cpu_time: Family::default(),
        ctx_switch: Family::default(),
        io_bytes: Family::default(),
    });
    let mut state = AppState {
        registry: Registry::default(),
    };
    state.registry.sub_registry_with_prefix("rdaemon").register(
        "requests",
        "Count of requests",
        metrics.requests.clone(),
    );
    state.registry.sub_registry_with_prefix("rdaemon").register(
        "cpu_seconds_time",
        "Count of cpu time",
        metrics.cpu_time.clone(),
    );
    state.registry.sub_registry_with_prefix("rdaemon").register(
        "ctx_switch",
        "Count of ctx switch",
        metrics.ctx_switch.clone(),
    );
    state.registry.sub_registry_with_prefix("rdaemon").register(
        "io_bytes",
        "Count of io bytes",
        metrics.io_bytes.clone(),
    );
    let state = web::Data::new(Mutex::new(state));

    HttpServer::new(move || {
        App::new()
            .wrap(middleware::Logger::default())
            .app_data(web::JsonConfig::default().limit(4096))
            .app_data(metrics.clone())
            .app_data(state.clone())
            .service(web::resource("/metrics").route(web::get().to(metrics_handler)))
            .service(web::resource("/processes").route(web::get().to(get_process_list)))
            .service(web::resource("/process/metrics").route(web::post().to(get_process_metrics)))
            .service(web::resource("/").route(web::post().to(index)))
    })
    .bind((args.addr, args.ports))?
    .run()
    .await
}
